;
; STOCK 810 ROM
;
; Automata states.
; Each bit has a different
; meaning and is used to
; know what should be done
; next.
;
AUT01    = $01
AUT02    = $02
AUTWAIT  = $04
AUTVER   = $08
AUT10    = $10
AUT20    = $20
AUT40    = $40
AUT80    = $80
;
; Command Status bits.
; Used in LSTATCMD.
;
STATNONE = $00
STATCMD  = $01
STATDATA = $02
STATERR  = $04
STATWP   = $08
STATACT  = $10
;
; Controller Status bits.
; Used in LSTATHW.
;
CTRLBUSY = $01
CTRLDRQ  = $02
CTRLLOST = $04
CTRLCRC  = $08
CTRLRNF  = $10
CTRLTYPE = $20
CTRLWP   = $40
CTRLMON  = $80
;
; Controller commands.
; These values are written
; into WCOMMAND register
; to ask the controller
; for a particular task.
;
WCMDWTRK = $F4
WCMDFINT = $D0
WCMDWSEC = $A8
WCMDRSEC = $88
WCMDSEEK = $13
WCMDREST = $00
;
; Inverted controller
; commands.
; Commands are written
; inverted int the
; controller regsiters.
;
IWCWTRK  = $FF-WCMDWTRK
IWCFINT  = $FF-WCMDFINT
IWCWSEC  = $FF-WCMDWSEC
IWCRSEC  = $FF-WCMDRSEC
IWCSEEK  = $FF-WCMDSEEK
IWCREST  = $FF-WCMDREST
;
; Length of Status answer
; Length of checksum
; Timeout for command
;
STATLEN  = $04
SUMLEN   = $01
TIMEOUT  = $E0
;
; Answer to a command.
;
ACK      = $41 ; 'A'
COMPLETE = $43 ; 'C'
ERROR    = $45 ; 'E'
NACK     = $4E ; 'N'
;
; WDC 1771 registers
;
WSTATUS  = $00 ; Read
WCOMMAND = $00 ; Write
WTRACK   = $01
WSECTOR  = $02
WDATA    = $03
;
; WDC base address
;
BASEWDC  = $0000
;
; WDC addresses
;
WDCSTAT  = BASEWDC+WSTATUS
WDCCOMND = BASEWDC+WCOMMAND
WDCTRACK = BASEWDC+WTRACK
WDCSECT  = BASEWDC+WSECTOR
WDCDATA  = BASEWDC+WDATA
;
; RIOT 6532 registers
;
DRA      = $00
DDRA     = $01
DRB      = $02
DDRB     = $03
EDGECTRL = $04
WR1NOIT  = $14
WR8NOIT  = $15
WR1IT    = $1C
WR64IT   = $1E
WR1024IT = $1F
;
; Port A bits
;
SWITCH1  = $01
DRVMOTOR = $02
SWITCH2  = $04
UNUSED   = $08
WPT1771  = $10
VSS6532  = $20
IRQ1771  = $40
DRQ1771  = $80
;
; Port B bits
;
DATAOUT  = $01
VCCRDY   = $02
PHASE4   = $04
PHASE3   = $08
PHASE2   = $10
PHASE1   = $20
COMMAND  = $40
DATAIN   = $80
;
; RIOT base address
;
BASERIOT = $0380
;
; RIOT addresses
;
RIOTDRA  = BASERIOT+DRA
RIOTDDRA = BASERIOT+DDRA
RIOTDRB  = BASERIOT+DRB
RIOTDDRB = BASERIOT+DDRB
RIOTEDGE = BASERIOT+EDGECTRL
RIOTW1NO = BASERIOT+WR1NOIT
RIOTW8NO = BASERIOT+WR8NOIT
RIOTW1   = BASERIOT+WR1IT
RIOTW64  = BASERIOT+WR64IT
RIOTW1K  = BASERIOT+WR1024IT
;
; Sector buffer
;
SECTOR   = $0080
;
; Code equates
;
L00E0    = $00E0
L00E1    = $00E1
L00E2    = $00E2
L00E3    = $00E3
L00F8    = $00F8
;
L0180    = $0180
LCMDDRV  = $0181
LCMDCMD  = $0182
LCMDAUX1 = $0183
LCMDAUX2 = $0184
LSNDBYTE = $0186
L0187    = $0187
LCURDRB  = $01CD
LCURTRK  = $01CE
L01CF    = $01CF
LSTATCMD = $01D0
LSTATHW  = $01D1
LSTATTIM = $01D2
LUNUSED  = $01D3
LSTATSUM = $01D4
LSAVAUX2 = $01D7
LSAVAUX1 = $01D8
LTRKNUM  = $01DA
LSECNUM  = $01DB
LAUTOM   = $01DD
LENDCMD  = $01DE
LPAUSE   = $01DF
L01E0    = $01E0
L01E1    = $01E1
L01E2    = $01E2
L01E3    = $01E3
L01E4    = $01E4
LJMPCMD  = $01E8
LOFSCMD  = $01EA
L01EB    = $01EB
;
; Start of code
;
         *= $0800
;
; Code starts here when
; the drive is turned on.
;
START    CLD
;
; Configure DRVMOTOR and
; UNUSED pins as output.
; All other pins (SWITCH1,
; SWITCH2, WPT1771,...)
; are input pins.
;
         LDA #DRVMOTOR+UNUSED
         STA RIOTDRA
         STA RIOTDDRA
;
; Configure PHASE1-4 pins
; as output. All other pins
; are input pins even
; DATAOUT so that no data is
; sent on the SIO bus now.
;
         LDX #PHASE1+PHASE2+PHASE3+PHASE4
         STX RIOTDDRB
         STX RIOTEDGE
         LDX #0
         STX RIOTDRB
;
; Stop current controller
; operation (if any) by
; sending a Force Interrupt
; command. This will fill
; the status register.
;
         LDA #IWCFINT
         STA WDCCOMND
;
; Remember to wait so that
; Force Interrupt command
; is not cancelled.
;
         LDA #AUTWAIT+AUT01
         STA LAUTOM
;
; Fill last part of status
; buffer returned on a
; GET STATUS command.
;
         LDA #TIMEOUT
         STA LSTATTIM
         LDA #0
         STA LUNUSED
;
; Sleep to let Force
; Interrupt command
; terminate.
;
         JSR LCHKWAIT
         LDY #$27
         JSR L0C8B
         STY WDCTRACK
         DEY
         STY WDCSECT
         JSR LCLRSTAT
         JSR LCHKPRT
         LDX #$01
         STX L01EB
;
; Reset stack.
; Get ready for the next
; command from the computer.
;
LRESSTK  LDX #$FF
         TXS
         LDA #$D8
         JSR L0C1B
         STY L01CF
;
; Restore head to track 0.
;
L084C    LDA #IWCREST
         STA WDCCOMND
         LDA #AUT20
;
; Jump over sector table
;
         JMP LOVERTBL
;
; Maybe unused...
; Who knows ?
;
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0
;
; 18 sector numbers
;
LFMTTAB  .BYTE $00,$FE,$FC,$FA
         .BYTE $F8,$F6,$F4,$F2
         .BYTE $F0,$EE,$FD,$FB
         .BYTE $F9,$F7,$F5,$F3
         .BYTE $F1,$EF
;
LOVERTBL JSR LORAUT
L0883    BIT RIOTDRA
         BVS L088E
         JSR L0CAB
         JMP L0883
L088E    DEC L01EB
         BPL L084C
L0893    LDX #$80
         LDY L01CF
         BEQ L08AA
         JSR L08ED
         STY L01CF
         JSR L0CAB
L08A3    LDA RIOTW8NO
         BPL L08A3
         BMI L0893
L08AA    LDA #UNUSED
         STA RIOTDRA
         LDA #0
         STA RIOTDRB
         LDA #$DF
         JSR LANDAUT
         LDA #AUTWAIT
         JSR LORAUT
         JMP L0CAB
;
; Check if sector number
; in DAUX1/DAUX2 is valid
; ($1 to $2D0).
;
LCHKSEC  LDX LCMDAUX2
         LDA LCMDAUX1
         BEQ LSECLOW
;
; Check high limit.
;
LSECHIGH CPX #$03
         BCS LSECERR
         CMP #$D1
         BCS LSECLAST
;
; Sector number is valid
;
LSECOK   CLC
         RTS
;
; Check low limit.
;
LSECLOW  CPX #0
         BNE LSECHIGH
;
; Sector number is out of
; range.
;
LSECERR  SEC
         RTS
;
; If DAUX1 is higher than
; $D0 then DAUX2 should not
; exceed $1.
;
LSECLAST CPX #$02
         BEQ LSECERR
         JMP LSECOK
         RTS
;
; Sleep for a certain amount
; of time.
;
LSLEEP   STA LPAUSE
LWAIT    DEY
         BNE LWAIT
         DEC LPAUSE
         BNE LWAIT
         RTS
L08ED    LDA #$29
         STA RIOTW64
         LDA RIOTDRB
         AND #PHASE1+PHASE2+PHASE3+PHASE4
         INX
         BMI L090C
         INC LCURTRK
         LSR A
         STA LCURDRB
         AND #$02
         BEQ L091E
         LDA #$20
         ORA LCURDRB
         BPL L0921
L090C    DEC LCURTRK
         ASL A
         STA LCURDRB
         AND #$40
         BEQ L091E
         LDA #$04
         ORA LCURDRB
         BPL L0921
L091E    LDA LCURDRB
L0921    STA RIOTDRB
         DEY
         RTS
;
; GET SECTOR
; ----------
;
LGET     JSR LCHKSEC
         BCS LBADSEC
;
; Wait for SIO COMMAND to
; be clear and send ACK to
; the computer.
;
         JSR LCMDACK
         JSR LMOTORON
         JSR LCHKWAIT
         JSR LSEEKTRK
L0937    LDA #IWCRSEC
         STA WDCCOMND
L093B    BVS L094C
         LDA RIOTW1
L0940    BIT RIOTDRA
         BPL L093B
         LDA WDCDATA
         INX
         STA SECTOR,X
         BPL L0940
L094C    JSR L0970
         BCS L0965
L0951    LDA #COMPLETE
L0953    STA LSNDBYTE
         JSR LCHKDATA
         STA L0187
         JSR LDATAOUT
         JSR L0E0F
         JMP LRESSTK
L0965    BNE L0937
L0967    LDA #ERROR
         JMP L0953
LBADSEC  JMP LBADCMD
         .BYTE $AD
L0970    LDA WDCSTAT
         STA LSTATHW
         EOR #$FF
         BNE L0984
         CLC
         LDA #$FB
         JSR LANDSTAT
L097F    JSR L0F68
         DEY
         RTS
L0984    CPY #$02
         BNE L09A3
         AND #CTRLRNF
         BEQ L09A3
         STY LPAUSE
         JSR LCHKWAIT
         LDY #$2B
         JSR L0C8B
         LDA LTRKNUM
         JSR L0C1B
         JSR L0F18
         LDY LPAUSE
L09A3    LDA #STATERR
         JSR LORSTAT
         SEC
         JMP L097F
;
; FORMAT
; ------
;
LFORMAT  JSR LCMDACK
         JSR LMOTORON
         JSR LCHKWAIT
         LDY #$2B
         JSR L0C8B
         JSR L0F63
         LDA RIOTDRA
         AND #WPT1771
         BEQ LNWPROT
         LDA #STATWP
         JSR LORSTAT
         JMP L0A95
LNWPROT  LDA #$FF
         STA L00E3
         JSR L09EB
L09D3    DEC L00E3
         LDA L00E3
         CMP #$D7
         BEQ L09E3
         LDX #$80
         JSR L09E8
         JMP L09D3
L09E3    JMP L0AA3
         BCS L09E8
L09E8    JSR L0B6D
L09EB    LDA #LFMTTAB&$FF
         STA L00E0
         LDA #LFMTTAB/256
         STA L00E1
         LDA RIOTW1NO
         LDA #$ED
         STA L00E2
         LDY #$FF
         LDX #$FF
         LDA #IWCWTRK
         STA WDCCOMND
         JSR L0A8D
         LDA #$0D
         STA RIOTW1K
         LDY #$FF
         JSR L0A80
         STX RIOTW1K
         LDY #$03
         JSR L0A8D
         LDY #$0B
         JSR L0A80
L0A1C    LDY #$06
         JSR L0A80
         LDY #$01
         JSR L0A8D
         LDY L00E3
         JSR L0A8D
         LDY #$FF
         JSR L0A8D
         LDY L00E2
         JSR L0A8D
         LDY #$FF
         JSR L0A8D
         LDY #$08
         JSR L0A8D
         LDY #$11
         JSR L0A80
         LDY #$04
         JSR L0A8D
         LDY #$80
         LDX #0
         JSR L0A80
         LDY #$08
         JSR L0A8D
         LDY #$09
         LDX #$FF
         JSR L0A80
         JSR L0A8D
         INC L00E0
         BMI L0A79
         JSR L0A8D
         LDA (L00E1,X)
         STA L00E2
         JMP L0A6F
L0A6D    BVS L0A95
L0A6F    BIT RIOTDRA
         BPL L0A6D
         STY WDCDATA
         JMP L0A1C
L0A79    LDA #IWCFINT
         STA WDCCOMND
         RTS
L0A7E    BVS L0A95
L0A80    BIT RIOTDRA
         BPL L0A7E
         STX WDCDATA
         DEY
         BNE L0A80
         RTS
L0A8B    BVS L0A95
L0A8D    BIT RIOTDRA
         BPL L0A8B
         STY WDCDATA
         RTS
L0A95    LDX #$FF
         STX SECTOR
         STX SECTOR+1
         LDA WDCSTAT
         STA LSTATHW
         JMP L0E71
L0AA3    LDX #0
         STX L01E1
L0AA8    LDA LCURTRK
         STA WDCTRACK
         LDA #$FE
L0AAF    STA LSECNUM
         STA WDCSECT
         LDY #$02
         STY L01E0
L0AB9    JSR L0F81
         LDY #$01
         JSR L0970
         BCS L0AF3
L0AC3    LDA LSECNUM
         SEC
         SBC #$04
         CMP #$EA
         BNE L0ACF
         LDA #$FB
L0ACF    CMP #$EB
         BNE L0AD5
         LDA #$FC
L0AD5    CMP #$EC
         BNE L0ADB
         LDA #$FD
L0ADB    CMP #$E9
         BNE L0AAF
         LDA LCURTRK
         CMP #$FF
         BEQ L0AF0
         LDX #0
         LDY #$01
         JSR L0F18
         JMP L0AA8
L0AF0    JMP L0E58
L0AF3    DEC L01E0
         BNE L0AB9
         LDX L01E1
         JMP L0E79
;
; Get DRVMOTOR bit from
; Port A.
;
LDRVBIT  LDA RIOTDRA
         LSR A
         LSR A
;
; Set the STATACT bit
; (active drive) in the
; command status byte
; if the DRVMOTOR bit
; is set.
;
         LDA #STATACT
         BCS LORSTAT
         LDA #STATNONE
;
; modify command status
; byte.
;
LORSTAT  ORA LSTATCMD
         STA LSTATCMD
         RTS
;
; Set command status byte
; by clearing it and ORing
; it with the Accumulator.
;
LSETSTAT PHA
         LDA #0
         AND LSTATCMD
         STA LSTATCMD
         PLA
         JMP LORSTAT
         RTS
LORAUT   ORA LAUTOM
         STA LAUTOM
         RTS
LANDAUT  AND LAUTOM
         STA LAUTOM
         RTS
;
; Clear all status bits
; except Write Protect flag.
;
LCLRSTAT LDA #STATWP
;
; Clear some status bits.
;
LANDSTAT AND LSTATCMD
         STA LSTATCMD
         RTS
L0B35    LDA RIOTDRB
         BPL L0B35
         TXA
         BEQ L0B67
         LDA L0180,X
         EOR #$FF
         STA L0180,X
L0B45    NOP
         NOP
         NOP
         LDY #$78
L0B4A    NOP
         NOP
         NOP
         NOP
         LDA RIOTDRB
         ROL A
         ROR LCMDDRV,X
         INY
         BPL L0B4A
         INX
         CPX LENDCMD
         BNE L0B35
         LDA L0180,X
         EOR #$FF
         STA L0180,X
         RTS
L0B67    NOP
         NOP
         NOP
         JMP L0B45
L0B6D    LDA #$02
         JSR LSLEEP
         JSR L08ED
         RTS
;
; Receive a sector (128 bytes)
; from computer. The byte is
; transmitted bit after bit
; through the DATAIN line of
; port B.
;
LRCVSEC  LDX #0
         LDY #$07
         STY LENDCMD
;
; Wait for the start bit.
;
LWSTART  LDA RIOTDRB
         BPL LWSTART
;
; Do not invert byte in the
; first iteration because we
; did not read any byte yet.
;
         TXA
         BEQ LRFIRST
;
; Invert all bits of the byte
; that has been received.
;
         LDA SECTOR-1,X
         EOR #$FF
         STA SECTOR-1,X
;
; Loop to receive all bytes.
;
LRCVBYTE NOP
         NOP
         NOP
         LDY #$78
;
; Loop to receive all bits of
; a byte.
;
LRCVBIT  NOP
         NOP
         NOP
         LDA SECTOR
;
; Get DATAIN line of port B
; and save it into SECTOR
; buffer.
;
         LDA RIOTDRB
         ROL A
         ROR SECTOR,X
;
; Next bit...
;
         INY
         BPL LRCVBIT
;
; Next byte...
;
         INX
         BPL LRCVNEXT
;
; All bytes have been received.
;
         LDX #$06
         JSR L0B35
         LDA L00F8,X
         EOR #$FF
         STA L00F8,X
         RTS
;
; One NOP for timing and get
; ready for next byte.
;
LRCVNEXT NOP
         JMP LWSTART
;
; Spend time to wait for the
; end of the start bit
; transmission.
;
LRFIRST  NOP
         NOP
         NOP
         JMP LRCVBYTE
;
; Compute a checksum of a
; command.
; Upon entry,
; - X contains the offset
;   of the command from the
;   label LCMDDRV.
; - Address LENDCMD contains
;   the last offset of the
;   command from the label
;   LCMDDRV.
; This subroutine returns
; the checksum in A.
;
LCHKSUM  LDA #0
         CLC
LCHKLOOP ADC LCMDDRV,X
         PHP
;
; Is it the last byte of the
; command ?
;
         INX
         CPX LENDCMD
;
; Last byte has been
; processed. Get out of the
; loop.
;
         BEQ LCHKEND
         PLP
         JMP LCHKLOOP
;
; The checksum is computed.
; We add the carry.
;
LCHKEND  PLP
         ADC #0
;
; Compare checksum with the
; one from the command. This
; is useful only with the
; command received from the
; computer.
;
         CMP LCMDDRV,X
         RTS
;
; Absolute sector number
; given in DAUX1/DAUX2 is
; converted into a track
; number and a sector number.
;
LCNVSEC  LDA LCMDAUX2
         STA LSAVAUX2
         LDA LCMDAUX1
         STA LSAVAUX1
;
; Sector number is divided
; by 16.
;
         LDX #$04
LCNVDIV  ROR LCMDAUX2
         ROR A
         DEX
         BNE LCNVDIV
         ROR LCMDAUX2
;
; LCMDAUX2 now contains in
; its 4 high bits the value
; of DAUX1 4 low bits.
; LCMDAUX2 is shifted right
; 4 times to have a value
; between $01 and $0F.
;
         LDX #$04
LCNVHI   LSR LCMDAUX2
         DEX
         BNE LCNVHI
;
; A contains absolute
; sector number divided
; by 16. A is multiplied
; by 2 to be compared to
; LCMDAUX2.
;
LCNVEND  ASL A
;
; If C is Clear, it means
; that A contains the track
; number multiplied by 2.
; If C is Set, it means
; that LCMDAUX2 should be
; adjusted to get the track
; number.
;
         CMP LCMDAUX2
         BCS LCNVSET
;
; A is divided by 2 to
; get the track number.
; It is saved inverted.
;
         STA LCMDAUX1
         LSR A
         EOR #$FF
         STA LTRKNUM
         SEC
         LDA LCMDAUX2
         SBC LCMDAUX1
         EOR #$FF
         STA LSECNUM
         RTS
;
; The division of LCMDAUX2
; by 16 has to be adjusted
; to get the track number.
;
LCNVSET  LSR A
         TAX
         DEX
         LDA #$10
         CLC
         ADC LCMDAUX2
         STA LCMDAUX2
         TXA
         JMP LCNVEND
L0C1B    LDX #0
         LDY #0
         SEC
         SBC LCURTRK
         BEQ L0C2F
         BPL L0C2E
         LDX #$80
         EOR #$FF
         CLC
         ADC #$01
L0C2E    TAY
L0C2F    RTS
;
; Check if disk is write
; protected and store the
; info in status byte.
;
LCHKPRT  LDA RIOTDRA
         AND #WPT1771
         BEQ LNOPRT
         LDA #STATWP
         JSR LORSTAT
         RTS
LNOPRT   LDA #$F7
         JSR LANDSTAT
         RTS
;
; Start drive motor (if not
; already started).
;
LMOTORON LDA RIOTDRA
;
; Check DRVMOTOR bit.
; If bit is set, it's OK.
;
         LSR A
         LSR A
         BCS L0C59
;
; Start drive motor now.
;
         LDA #DRVMOTOR+UNUSED
         STA RIOTDRA
         STA WDCDATA
         LDA #$16
         STA WDCTRACK
         LDA #IWCSEEK
         STA WDCCOMND
L0C59    LDA #$01
         STA L01EB
         RTS
L0C5F    LDA LAUTOM
         LSR A
         LSR A
         LSR A
         BCC L0C71
L0C67    BIT RIOTDRA
         BVC L0C67
         LDA #$FB
         JSR LANDAUT
L0C71    LDA #STATACT
         JSR LSETSTAT
         RTS
;
; Wait for the SIO COMMAND
; bit to be clear.
;
LCMDACK  BIT RIOTDRB
         BVS LCMDACK
;
; Send an ACK byte to the
; Atari
;
LSENDACK LDA #ACK
;
; Send a byte from the
; Accumulator to the Atari.
;
LSEND    STA LSNDBYTE
         JSR LDATAOUT
         JSR LSNDDATA
         JSR LNODATA
         RTS
L0C8B    LDX #PHASE1+PHASE4
         STX RIOTDRB
L0C90    JSR L08ED
         BMI L0C9D
L0C95    LDA RIOTW8NO
         BPL L0C95
         JMP L0C90
L0C9D    STY LCURTRK
         TXA
         LDX #$14
L0CA3    DEY
         BNE L0CA3
         DEX
         BNE L0CA3
         TAX
         RTS
L0CAB    LDA RIOTDRB
         LSR A
         LSR A
         BCS L0CE4
         LDA LAUTOM
         LSR A
         BCS L0CD7
         BIT RIOTDRB
         BVC L0CCC
         BIT LAUTOM
         BVC L0CEC
         LDA #$29
         JSR LSLEEP
         BIT RIOTDRB
         BVS L0CEC
L0CCC    LDA LAUTOM
         AND #AUT40+AUT20
         BNE L0CD6
         JMP L0CAB
L0CD6    RTS
L0CD7    LDA #$29
         JSR LSLEEP
         LDA #$FE
         JSR LANDAUT
         JMP L0CAB
L0CE4    LDA #AUT01
         JSR LORAUT
         JMP L0CCC
L0CEC    LDA #AUT80
         JSR LORAUT
         LDX #0
         LDA #$05
         STA LENDCMD
         JSR L0B35
         LDX #0
         DEC LENDCMD
         JSR LCHKSUM
         BEQ LREADCFG
         LDA #AUT02
         JSR LORAUT
;
; Get drive number from
; the switches at the rear
; of the drive. This is
; done by reading 2 bits
; from Port A of the 6532.
; Here are the possible
; values:
;
; SWITCH1 SWITCH2 Drive
;   ON      ON      1
;   OFF     ON      2
;   OFF     OFF     3
;   ON      OFF     4
;
; X will hold the drive
; number (by default 4):
;
LREADCFG LDX #$34
;
; Read port A and keep only
; bits from the 2 switches.
;
         LDA RIOTDRA
         AND #SWITCH1+SWITCH2
;
; Switch configuration:
; SWITCH1 SWITCH2 Drive
;   OFF     OFF     3
;
         BEQ LDRV3
;
; Switch configuration:
; SWITCH1 SWITCH2 Drive
;   OFF     ON      2
;
         CMP #SWITCH2
         BEQ LDRV2
;
; Switch configuration:
; SWITCH1 SWITCH2 Drive
;   ON      OFF     4
;
         CMP #SWITCH1
         BEQ LDRV4
;
; Switch configuration:
; SWITCH1 SWITCH2 Drive
;   ON      ON      1
;
         DEX
LDRV2    DEX
LDRV3    DEX
;
; X now holds the drive
; number ($31-$34) from the
; switches. Check that the
; command is for our drive.
;
LDRV4    CPX LCMDDRV
         BEQ LDRVOK
;
; Command is not for our
; drive. Wait for the SIO
; COMMAND bit to be clear.
;
LCMDSET1 BIT RIOTDRB
         BVS LCMDSET1
         LDA #$7D
         JSR LANDAUT
         JMP L0CAB
;
; Check command sent
; by computer.
;
LDRVOK   JSR LCHKCMD
         JMP L0CAB
;
; GET STATUS
; ----------
;
LSTATUS  JSR LSENDACK
;
; Compute checksum on the
; status frame answer.
;
         LDX #LSTATCMD-LCMDDRV
         LDY #LSTATCMD-LCMDDRV+STATLEN
         STY LENDCMD
         JSR LCHKSUM
;
; Store checksum at the
; end of the status frame
; answer.
;
         STA LSTATSUM
;
; Send a COMPLETE code to
; the computer.
;
         LDA #COMPLETE
         STA LSNDBYTE
         JSR LDATAOUT
;
; X will hold the count of
; bytes to send.
; The loop ends when reg X
; reaches $80. X is set to
; $80 minus the COMPLETE
; byte, minus the 4 bytes
; of the status answer and
; minus the checksum byte.
;
         LDX #$80-1-STATLEN-SUMLEN
         JSR LSNDDATA
;
; Send all status bytes to
; the computer.
;
LSTATLP  LDY LSTATCMD-$80+STATLEN+SUMLEN,X
         STY LSNDBYTE
         JSR LSNDDAT2
         BPL LSTATLP
;
; All bytes have been sent.
; Turn off DATA OUT line.
;
         JSR LNODATA
;
; Reset all status bits
; except Write Protect then
; set Activity bit according
; to the WD1771 status.
;
         JSR LCLRSTAT
         JSR LDRVBIT
         JMP LRESSTK
L0D6A    LDY #0
         STY L01E4
         LDA LSECNUM
         EOR #$FF
         STA L01E2
         LDA LCURTRK
         EOR #$FF
         ASL A
         STA L01E3
         ASL A
         ASL A
         ROL L01E4
         ASL A
         ROL L01E4
         ADC L01E3
         TAY
         LDA #0
         ADC L01E4
         JMP L0DDF
;
; ?
;
LCHKCMD  LDA LAUTOM
         LSR A
         LSR A
         BCS LBADCMD
;
; The command should be in
; the range of $4F to $57.
;
         LDA LCMDCMD
         CMP #$4F
         BCC LISFMT
         CMP #$58
         BCS LISFMT
;
; Command is converted
; to a Jump address.
; The 3 low bits of the
; command byte are
; multiplied by 3.
; Appearently, $4F is the
; same as $57.
;
         AND #$07
         STA LOFSCMD
         ASL A
         ADC LOFSCMD
;
; Then, the result is
; added to LTABCMD address.
;
         ADC #LTABCMD&$FF
         STA LJMPCMD
         LDA #0
         ADC #LTABCMD/256
         STA LJMPCMD+1
;
; Execute the routine
; corresponding to
; the command.
;
         JMP (LJMPCMD)
;
; Is command equal to
; $21 (format).
;
LISFMT   CMP #$21
         BEQ LJMPFMT
;
; The command sent is
; unknown !
;
LBADCMD  LDA #STATCMD
         JSR LSETSTAT
         JSR LDRVBIT
;
; Wait for the SIO COMMAND
; bit to be clear.
;
LCMDSET2 BIT RIOTDRB
         BVS LCMDSET2
;
; Send NACK to the Atari.
;
         LDA #NACK
         JSR LSEND
         LDA #$FD
         JSR LANDAUT
         RTS
;
; Jump to format routine
;
LJMPFMT  JMP LFORMAT
         .BYTE $01
L0DDF    STA L01E4
         TYA
         CLC
         ADC L01E2
         STA SECTOR,X
         LDA #0
         ADC L01E4
         INX
         STA SECTOR,X
         RTS
;
; Compute data checksum
; and check it.
;
LCHKDATA LDA #0
         TAX
         CLC
LADDBYTE ADC SECTOR,X
         INX
         BPL LADDBYTE
         ADC #0
         CMP L0187
         RTS
;
; Set DATAOUT line of port B
; as an output line.
;
LDATAOUT LDX RIOTDRB
         STX RIOTDRB
         LDX RIOTDDRB
         INX
         STX RIOTDDRB
         RTS
L0E0F    LDX #$FF
         JSR LSNDDATA
L0E14    LDY SECTOR,X
         STY LSNDBYTE
         JSR LSNDDAT2
         BPL L0E14
         LDY L0187
         STY LSNDBYTE
         JSR LSNDDAT2
;
; Set DATAOUT line of Port B
; as an input line: No more
; data is sent to the Atari.
;
LNODATA  LDX RIOTDDRB
         DEX
         STX RIOTDDRB
         RTS
;
; Send a byte to the Atari.
; Each bit of the byte is
; put on the DATAOUT line of
; Port B (LSB bit first).
;
LSNDDATA LDA RIOTDRB
;
; A start bit (value 0) is
; sent before the byte.
;
LSNDDAT2 AND #$FE
         STA RIOTDRB
;
; Y register will hold the
; bit counter (from $78 to
; $80).
;
         LDY #$78
         BIT SECTOR
LSNDLOOP BIT SECTOR
         NOP
         NOP
;
; Send one bit from LSNDBYTE.
;
         LSR A
         ROR LSNDBYTE
         ROL A
         STA RIOTDRB
         INY
         BPL LSNDLOOP
;
; A stop bit (value 1) is
; sent after the byte.
;
         LSR A
         SEC
         ROL A
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         STA RIOTDRB
         INX
         RTS
L0E58    LDA #$FF
         LDX L01E1
         STA SECTOR,X
         INX
         STA SECTOR,X
         LDA LAUTOM
         AND #AUTVER
         BNE L0E6C
         JMP L0951
L0E6C    LDA #$F7
         JSR LANDAUT
L0E71    LDA #STATERR
         JSR LORSTAT
         JMP L0967
L0E79    LDA #AUTVER
         JSR LORAUT
         JSR L0D6A
         INX
         STX L01E1
         CPX #$7E
         BNE L0E8C
         JMP L0E58
L0E8C    JMP L0AC3
;
; This is the jump table
; for the drive commands.
; The table is the following:
;
; Command Meaning
;   $50   PUT SECTOR
;   $51   UNUSED
;   $52   GET SECTOR
;   $53   GET STATUS
;   $54   UNUSED
;   $55   UNUSED
;   $56   UNUSED
; $4F/$57 PUT SECTOR VERIFY
;
LTABCMD  JMP LPUT
         JMP LBADCMD
         JMP LGET
         JMP LSTATUS
         JMP LBADCMD
         JMP LBADCMD
         JMP LBADCMD
         JMP LPUTVER
;
; Wait for SIO COMMAND to
; be clear and send ACK to
; computer.
;
LDOPUT   JSR LCMDACK
         JSR LMOTORON
         JSR LRCVSEC
         JSR LCHKDATA
         BNE LBADDATA
         JSR LSENDACK
         JSR LCHKWAIT
         JSR LSEEKTRK
         LDA RIOTDRA
         AND #WPT1771
         BNE LWPROT
L0EC5    LDA #IWCWSEC
         STA WDCCOMND
L0EC9    BVS L0EE5
         LDA RIOTW1
         BIT RIOTDRA
         BMI L0EDD
         JMP L0EC9
L0ED6    BVS L0EE5
L0ED8    BIT RIOTDRA
         BPL L0ED6
L0EDD    INX
         LDA SECTOR,X
         STA WDCDATA
         JMP L0ED8
L0EE5    JSR L0970
         LDA #ERROR
         BCS L0F42
         LDA LAUTOM
         AND #AUTVER
         BEQ L0EFC
         JSR L0F9D
         BCC L0EFC
         LDA #ERROR
         BCS LSENDRES
L0EFC    LDA #COMPLETE
L0EFE    JMP LSENDRES
LBADDATA LDA #STATACT+STATDATA
         JSR LSETSTAT
         LDA #NACK
LSENDRES JSR LSEND
         JMP LRESSTK
LWPROT   LDA #STATERR+STATWP
         JSR LORSTAT
         LDA #ERROR
         JMP LSENDRES
L0F18    BEQ L0F31
L0F1A    JSR L08ED
         BEQ L0F27
L0F1F    LDA RIOTW8NO
         BPL L0F1F
         JMP L0F1A
L0F27    LDA #$50
         STA RIOTW64
L0F2C    LDA RIOTW8NO
         BPL L0F2C
L0F31    RTS
;
; PUT SECTOR with VERIFY
; ----------------------
;
LPUTVER  LDA #AUTVER
         JSR LORAUT
;
; PUT SECTOR
; ----------
;
LPUT     JSR LCHKSEC
         BCS L0F3F
         JMP LDOPUT
L0F3F    JMP LBADCMD
L0F42    CPY #0
         BEQ L0F49
         JMP L0EC5
L0F49    BEQ L0EFE
;
; Convert absolute sector
; number to a track and
; a sector number then
; seek to the track.
;
LSEEKTRK JSR LCNVSEC
         LDA RIOTDRB
         AND #PHASE1+PHASE2+PHASE3+PHASE4
         BNE L0F5A
         LDA #PHASE1+PHASE2
         STA RIOTDRB
L0F5A    LDA LTRKNUM
         JSR L0C1B
         JSR L0F18
L0F63    JSR L0C5F
         LDY #$04
L0F68    LDA #IWCFINT
         STA WDCCOMND
         LDX #$FF
L0F6E    DEX
         BNE L0F6E
         LDA LTRKNUM
         STA WDCTRACK
         LDA LSECNUM
         STA WDCSECT
         CLV
         DEX
         STX RIOTW1K
         RTS
L0F81    JSR L0F68
         LDA LCURTRK
         STA WDCTRACK
         LDA #IWCRSEC
         STA WDCCOMND
L0F8D    BVS L0F9C
         LDA RIOTW1
L0F92    BIT RIOTDRA
         BPL L0F8D
         LDA WDCDATA
         JMP L0F92
L0F9C    RTS
L0F9D    JSR L0F68
         LDY #$01
L0FA2    INX
         LDA #IWCRSEC
         STA WDCCOMND
L0FA7    BVS L0FBA
         LDA RIOTW1
L0FAC    BIT RIOTDRA
         BPL L0FA7
         LDA WDCDATA
         CMP SECTOR,X
         BNE L0FC7
         INX
         BNE L0FAC
L0FBA    JSR L0970
         BCC L0FC1
         BPL L0FA2
L0FC1    LDA #$F7
         JSR LANDAUT
         RTS
L0FC7    JSR L09A3
         JMP L0FC1
;
; Check the automata to
; see if we have to sleep.
;
LCHKWAIT LDA LAUTOM
         AND #AUTWAIT
         BEQ LNOWAIT
         LDA #$50
         JSR LSLEEP
LNOWAIT  RTS
;
; This is just a padding so
; that the last two WORDs
; starts at address $0FFC
; and $0FFE.
;
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0,0,0,0,0,0,0
         .BYTE 0,0
;
; START is both the IRQ
; and RESET address.
;
; IMPORTANT: if you modify
; this source, always check
; that this word is at
; address $0FFC. If not, add
; or remove some of the
; padding bytes above.
;
         .WORD START ; RESET
         .WORD START ; IRQ
;
         .END